Skip to content

Conversation

@odersky
Copy link
Contributor

@odersky odersky commented Apr 30, 2015

Review by @DarkDimius (in particular 66e9ea8), @adriaanm

@DarkDimius
Copy link
Contributor

LTGM otherwise.

@adriaanm
Copy link
Contributor

Cool! Nice approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this restriction comes from? Currently Dotty uses LambdaMetaFactory for this case and it works fine at runtime, also Exception is a subclass of Object so I don't understand what a "non-object class" is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"non-object class": class other than java.lang.Object.

The problem is in the runtime types. If we write

val lambda = (x => e): C

we expect that lambda.isInstanveOf[C].

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it works fine at runtime

It does not. LambdaMetaFactory explicitly checks that invokedType returns an interface.
This is both spec'd and implemented.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

object O {
  abstract class D {
    def foo(a: Int): Int
  }

  def main(args: Array[String]): Unit = {
    val a: D = x => x
    a.foo(1)
  }
}
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
    at java.lang.invoke.CallSite.makeSite(CallSite.java:328)
    at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:296)
    at O$.main(CLM.scala:5)
    at O.main(CLM.scala)
Caused by: java.lang.invoke.LambdaConversionException: Functional interface O$$D is not an interface
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:145)
    at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
    at java.lang.invoke.CallSite.makeSite(CallSite.java:289)
    ... 3 more

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we expect that lambda.isInstanceOf[C].

This is the case in this example:

object Foo {
  trait V extends Exception { def foo(x: Int): Int }

  val v: V = (x: Int) => 2

  def main(args: Array[String]): Unit = {
    println(v.isInstanceOf[V])
  }
}

In master right now it will print "true". This makes sense: for each trait, Dotty will generate an interface, and LambdaMetaFactory will return an instance of that interface.

@DarkDimius : Your example is something else entirely: abstract class should not be SAM types, only traits can be SAM types.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@smarter, yes, this is something else entirely, and this is what is tested here.
Quoting Martin:

"non-object class": class other than java.lang.Object.

In this example, trait V extends class Exception. So it could not be implemented by a JVM SAM.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you want your test to fail, try to test if v.isInstanceOf[Exception].

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I get it now, thanks.

odersky added 13 commits May 2, 2015 19:06
It's common that one wants to create class symbols with arbitary parent types,
not just TypeRefs. But for the casual user it's non-obvious how to do it.
Hence the new creation method.
The handling of the first parent of ClassDef was broken if
that parent had type parameters. This was exposed by following
commites which use ClassDef more intensively than before in
creating anonymous classes representing closures.
As the name implies, this creates an anonymous class.
The phase replaces SAM closures with anonymous classes when necessary.
Like all other variables, pattern-bound vars need a fully defined type. I was
thinking originally that demanding a fully defined selector type is sufficient
to ensure this, but that's not true: An outer pattern might call a polymorphic
unapply and its type variables need not be fully instantiated.

With the fix, the minimized test case from ExpandSAMs works.
Removed the workaround of the original crasher which was addressed in the last commit.
Now takes a list of parent types. We needed only one parent for SAM implementation
but it makes sense to generalize this.

Also, removed redundant code accidentally left in.
Thanks for pointing it out, @smarter.
superClass was a duplicate; we already have one in SymDenotation,
so we delete the one in SymUtils.

superInterfaces is too easy to confused with the JVM notion, which
is different. I replaced with directlyInheritedTraits.
Also included are

  - Closures implementing classes that inherit from a class other than Object
  - Closures that implement traits which run initialization code.
The test included here fails in backend.
@odersky
Copy link
Contributor Author

odersky commented May 2, 2015

Rebased to current master.

@DarkDimius
Copy link
Contributor

LGTM.

DarkDimius added a commit that referenced this pull request May 4, 2015
Expand SAM closures to anonymous classes if needed
@DarkDimius DarkDimius merged commit c4dba24 into scala:master May 4, 2015
@allanrenucci allanrenucci deleted the add/expandSAMs branch December 14, 2017 16:57
tgodzik added a commit that referenced this pull request Aug 13, 2025
Backport "Fix #22922: Add TypeParamRef handling in isSingletonBounded" to 3.3 LTS
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants